package cn.wbu.zyh.service.impl;

import cn.wbu.zyh.dto.*;
import cn.wbu.zyh.entity.*;
import cn.wbu.zyh.mapper.*;
import cn.wbu.zyh.result.PageResult;
import cn.wbu.zyh.service.ArticleService;
import cn.wbu.zyh.vo.ArticleVO;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
@CacheConfig(cacheNames = "articleCache") // 统一指定本类中的缓存名
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private TagMapper tagMapper;
    @Autowired
    private ArticleTagMapper articleTagMapper;
    @Autowired
    private FavoritesMapper favoritesMapper;
    @Autowired
    private AnnotationMapper annotationMapper;
    @Autowired
    private TeamArticleMapper teamArticleMapper;

    /**
     * 根据笔记 ID 获取笔记及其标签、注解、协作人等信息
     */
    @Override
    // key默认为方法参数，可自定义 key，示例如: key = "#id"
    @Cacheable(key = "#id")
    public ArticleVO getByIdWithTags(Long id) {
        log.info("从数据库查询 getByIdWithTags，id = {}", id);
        Article article = articleMapper.getById(id);
        List<ArticleTag> articleTags = articleTagMapper.getByArticleId(id);
        List<Annotation> annotations = annotationMapper.getByNoteId(id);
        List<TeamArticle> teamArticles = teamArticleMapper.getByNoteId(id);

        ArticleVO articleVO = new ArticleVO();
        BeanUtils.copyProperties(article, articleVO);
        articleVO.setArticleTags(articleTags);
        articleVO.setAnnotations(annotations);
        articleVO.setTeamArticle(teamArticles);

        return articleVO;
    }

    /**
     * 标签 ID 分页查询笔记
     */
    @Override
    // 这里演示：根据标签ID分页查询，你也可以把 page、pageSize、tagId 都纳入 key
    @Cacheable(key = "'tagId:' + #tagPageQueryDTO.id + ':page:' + #tagPageQueryDTO.page + ':size:' + #tagPageQueryDTO.pageSize")
    public PageResult pageQueryByTagId(TagPageQueryDTO tagPageQueryDTO) {
        PageHelper.startPage(tagPageQueryDTO.getPage(), tagPageQueryDTO.getPageSize());
        Page<Article> page = articleMapper.pageQueryByTagId(tagPageQueryDTO.getId());
        long total = page.getTotal();
        List<Article> records = page.getResult();
        return new PageResult(total,records);
    }

    /**
     * 普通分页查询 或 查询当前用户收藏的笔记
     */
    @Override
    // 同理，把 isFavorite、page、pageSize 等拼接到 key 中
    @Cacheable(key = "'pageQuery:' + #articlePageQueryDTO.toString()")
    public PageResult pageQuery(ArticlePageQueryDTO articlePageQueryDTO) {
        log.info("从数据库查询 pageQuery, articlePageQueryDTO = {}", articlePageQueryDTO);

        PageHelper.startPage(articlePageQueryDTO.getPage(), articlePageQueryDTO.getPageSize());
        Boolean isFavorite = articlePageQueryDTO.getIsFavorite();
        Page<Article> page;
        if (isFavorite != null && isFavorite) {
            page = articleMapper.findFavoriteArticlesByUser(articlePageQueryDTO);
        } else {
            page = articleMapper.pageQuery(articlePageQueryDTO);
        }
        long total = page.getTotal();
        List<Article> records = page.getResult();

        return new PageResult(total, records);
    }

    /**
     * 新增笔记
     */
    @Override
    @Transactional
    // 新增笔记后，为了让“笔记列表、笔记详情”等缓存失效，可以用 @CacheEvict
    // 例如让所有和“articleCache”相关的 key 都失效（allEntries = true），也可以只精确失效。
    @CacheEvict(allEntries = true)
    public void saveWithTag(ArticleDTO articleDTO) {
        Article article = new Article();
        BeanUtils.copyProperties(articleDTO, article);
        articleMapper.insert(article);

        Long articleId = article.getId();
        List<ArticleTag> articleTags = articleDTO.getArticleTags();
        if (articleTags != null && !articleTags.isEmpty()) {
            for (ArticleTag articleTag : articleTags) {
                Tag existingTag = tagMapper.findByNameAndUser(articleTag.getName(), article.getCreatedUser());
                if (existingTag == null) {
                    Tag newTag = new Tag();
                    newTag.setName(articleTag.getName());
                    newTag.setCreatedUser(article.getCreatedUser());
                    tagMapper.insert(newTag);
                    articleTag.setTagId(newTag.getId());
                } else {
                    articleTag.setTagId(existingTag.getId());
                }
                ArticleTag newArticleTag = new ArticleTag();
                newArticleTag.setArticleId(articleId);
                newArticleTag.setTagId(articleTag.getTagId());
                articleTagMapper.insert(newArticleTag);
            }
        }
    }

    /**
     * 更新笔记
     */
    @Override
    @Transactional
    // 更新操作后，需要更新(或清空)缓存，保证后续从缓存取到的是最新数据
    // 这里演示：清空全部缓存(allEntries = true)。如果需求是“只清理当前 ID”，可用 key = "#articleDTO.id"
    @CacheEvict(allEntries = true)
    public void update(ArticleDTO articleDTO) {
        Article article = new Article();
        BeanUtils.copyProperties(articleDTO, article);
        articleMapper.update(article);
        Long articleId = article.getId();

        // 更新文章标签
        updateArticleTags(articleDTO, articleId);

        // 更新注释
        updateAnnotations(articleDTO, articleId);

        // 更新协作者
        updateTeamArticles(articleDTO, articleId);
    }

    private void updateArticleTags(ArticleDTO articleDTO, Long articleId) {
        // 先清除，再插入
        articleTagMapper.deleteByArticleId(articleId);
        List<ArticleTag> articleTags = articleDTO.getArticleTags();
        if (articleTags != null && !articleTags.isEmpty()) {
            List<ArticleTag> newArticleTags = new ArrayList<>();
            for (ArticleTag articleTag : articleTags) {
                Tag tag = tagMapper.findByNameAndUser(articleTag.getName(), articleDTO.getCreatedUser());
                if (tag == null) {
                    tag = new Tag();
                    tag.setName(articleTag.getName());
                    tag.setCreatedUser(articleDTO.getCreatedUser());
                    tagMapper.insert(tag);
                }
                ArticleTag newArticleTag = new ArticleTag();
                newArticleTag.setArticleId(articleId);
                newArticleTag.setTagId(tag.getId());
                newArticleTags.add(newArticleTag);
            }
            if (!newArticleTags.isEmpty()) {
                articleTagMapper.insertBatch(newArticleTags);
            }
        }
    }

    private void updateAnnotations(ArticleDTO articleDTO, Long articleId) {
        annotationMapper.deleteByArticleId(articleId);
        List<Annotation> annotations = articleDTO.getAnnotations();
        if (annotations != null && !annotations.isEmpty()) {
            annotations.forEach(annotation -> annotation.setArticleId(articleId));
            annotationMapper.insertAnnotationsBatch(annotations);
        }
    }

    private void updateTeamArticles(ArticleDTO articleDTO, Long articleId) {
        teamArticleMapper.deleteByArticleId(articleId);
        List<TeamArticle> teamArticles = articleDTO.getTeamArticle();
        if (teamArticles != null && !teamArticles.isEmpty()) {
            teamArticles.forEach(teamArticle -> {
                teamArticle.setArticleId(articleId);
                teamArticleMapper.addCollaborator(teamArticle);
            });
        }
    }

    /**
     * 删除笔记
     */
    @Override
    @Transactional
    // 删除笔记后，要让缓存失效
    @CacheEvict(allEntries = true)
    public void deleteAticle(Long id) {
        articleTagMapper.deleteByArticleId(id);
        articleMapper.deleteById(id);
        teamArticleMapper.deleteByArticleId(id);
    }

    @Override
    @Cacheable(
            key = "'teamArticle:' + #teamArticlePageQueryDTO.teamId + " +
                    "':user:' + #teamArticlePageQueryDTO.username + " +
                    "':page:' + #teamArticlePageQueryDTO.page + " +
                    "':size:' + #teamArticlePageQueryDTO.pageSize"
    )
    public PageResult TeamArticlePageQuery(TeamArticlePageQueryDTO teamArticlePageQueryDTO) {
        log.info("从数据库查询 TeamArticlePageQuery, 入参 = {}", teamArticlePageQueryDTO);
        PageHelper.startPage(teamArticlePageQueryDTO.getPage(), teamArticlePageQueryDTO.getPageSize());
        Page<Article> page = articleMapper.pageQueryByTeamId(teamArticlePageQueryDTO.getTeamId(), teamArticlePageQueryDTO.getUsername());
        long total = page.getTotal();
        List<Article> records = page.getResult();
        return new PageResult(total, records);
    }

}